/*=============================================================================
  ShaderScript.cpp : loading/reloading/hashing of shader scipts.
  Copyright (c) 2001 Crytek Studios. All Rights Reserved.

  Revision history:
    * Created by Honich Andrey

=============================================================================*/

#include "StdAfx.h"
#include "I3DEngine.h"
#include "CryHeaders.h"

#if defined(WIN32) || defined(WIN64)
#include <direct.h>
#include <io.h>
#endif

#ifdef WIN64
#pragma warning( push )									//AMD Port
#pragma warning( disable : 4267 )
#endif

extern char *gShObjectNotFound;

//=================================================================================================

bool CShader::Reload(int nFlags, const char *szShaderName)
{
	CShader *pShaderGen = NULL;
	if (m_ShaderGenParams)
		pShaderGen = this;
	else
		if (m_pGenShader)
			pShaderGen = m_pGenShader;
	uint32 nFl = EF_RELOAD;
	if (nFlags & FRO_FORCERELOAD)
		nFl |= EF_FORCE_RELOAD;
	if (pShaderGen)
	{
		for (uint32 i=0; i<pShaderGen->m_DerivedShaders->size(); i++)
		{
			CShader *pShader = (*pShaderGen->m_DerivedShaders)[i];
			if (!pShader)
				continue;
			if (pShader->m_nRefreshFrame == gRenDev->m_cEF.m_nFrameForceReload)
				continue;
			pShader->m_nRefreshFrame = gRenDev->m_cEF.m_nFrameForceReload;

			gRenDev->m_cEF.mfForName(szShaderName, pShader->m_Flags | nFl, NULL, pShader->m_nMaskGenFX);
		}
	}
	else
	{
		assert(!m_nMaskGenFX);
		gRenDev->m_cEF.mfForName(szShaderName, m_Flags | nFl, NULL, m_nMaskGenFX);
	}

	return true;
}

bool CShaderMan::mfReloadShaderIncludes(const char *szPath, int nFlags)
{
	assert(szPath);

	bool bChanged = false;
	char dirn[256];
	strcpy(dirn, szPath);
	strcat(dirn, "*.*");
	struct _finddata_t fileinfo;
	intptr_t handle = gEnv->pCryPak->FindFirst (dirn, &fileinfo);
	if (handle != -1)
	{
		do
		{
			if (fileinfo.name[0] == '.')
				continue;
			if (fileinfo.attrib & _A_SUBDIR)
			{
				char ddd[256];
				sprintf(ddd, "%s%s/", szPath, fileinfo.name);

				bChanged = mfReloadShaderIncludes(ddd, nFlags);
				continue;
			}
			char nmf[256];
			strcpy_s(nmf, szPath);
			strcat_s(nmf, fileinfo.name);
			int len = strlen(nmf) - 1;
			while (len >= 0 && nmf[len] != '.')
				len--;
			if (len <= 0)
				continue;
			if (!stricmp(&nmf[len], ".cfi"))
			{
				fpStripExtension(fileinfo.name, nmf);
				bool bCh = false;
				SShaderBin *pBin = m_Bin.GetBinShader(nmf, true, 0, &bCh);
				if (bCh)
				{
					bChanged = true;
					mfReloadFile(szPath, fileinfo.name, nFlags);
				}
			}
		} while (gEnv->pCryPak->FindNext(handle, &fileinfo) != -1);

		gEnv->pCryPak->FindClose (handle);
	}
  return bChanged;
}

bool CShaderMan::mfReloadAllShaders(int nFlags, uint32 nFlagsHW)
{
	bool bState = true;
	m_nFrameForceReload++;

	gRenDev->FlushRTCommands(true, true, true);
	m_Bin.InvalidateCache();
	CHWShader::mfFlushPendedShadersWait(-1);

#ifndef NULL_RENDERER

	CDebugAllowFileAccess ignoreInvalidFileAccess;

	// Check include changing
	if (m_ShadersPath && !CRenderer::CV_r_shadersignoreincludeschanging)
	{
		bool bChanged = mfReloadShaderIncludes(m_ShadersPath, nFlags);
	}
	CCryNameTSCRC Name = CShader::mfGetClassName();
	SResourceContainer *pRL = CBaseResource::GetResourcesForClass(Name);
	if (pRL)
	{
		ResourcesMapItor itor;
		for (itor=pRL->m_RMap.begin(); itor!=pRL->m_RMap.end(); itor++)
		{
			CShader *pS = (CShader *)itor->second;
			if (!pS)
			continue;
			if (nFlagsHW)
			{
				if (!pS->m_pGenShader)
					continue;
				SShaderGen *pGen = pS->m_pGenShader->m_ShaderGenParams;
				assert(pGen);
				if (!pGen)
					continue;
				uint32 i;
				SShaderGenBit *pBit;
				for (i=0; i<pGen->m_BitMask.Num(); i++)
				{
					pBit = pGen->m_BitMask[i];
					if ((pBit->m_nDependencySet | pBit->m_nDependencyReset) & nFlagsHW)
						break;
				}
				if (i == pGen->m_BitMask.Num())
					continue;
				pS->Reload(nFlags | FRO_FORCERELOAD, pS->GetName());
			}
			else
			{
				char name[256];
				sprintf(name, "%sCryFX/%s.cfx", m_ShadersPath, pS->GetName());
				FILE *fp = gEnv->pCryPak->FOpen(name, "rb");
				if (fp)
				{
					uint32 nSourceCRC32 = gEnv->pCryPak->ComputeCRC(name);
					gEnv->pCryPak->FClose(fp);
					if ((nFlags & FRO_FORCERELOAD) || nSourceCRC32 != pS->m_SourceCRC32)
					{
						pS->m_SourceCRC32 = nSourceCRC32;
						pS->Reload(nFlags, pS->GetName());
					}
				}
			}
		}
	}
#endif

	gRenDev->FlushRTCommands(true, true, true);
	CHWShader::mfFlushPendedShadersWait(-1);

	return bState;
}

static bool sCheckAffecting_r(SShaderBin *pBin, const char *szShaderName)
{
	int nTok = 0;
	// Check first level
	while (nTok >= 0)
	{
		nTok = CParserBin::FindToken(nTok, pBin->m_Tokens.size()-1, &pBin->m_Tokens[0], eT_include);
		if (nTok >= 0)
		{
			nTok++;
			uint32 nTokName = pBin->m_Tokens[nTok];
			const char *szNameInc = CParserBin::GetString(nTokName, pBin->m_TokenTable);
			if (!stricmp(szNameInc, szShaderName))
				break;
		}
	}
	// Check recursively
	if (nTok < 0)
	{
	nTok = 0;
	while (nTok >= 0)
	{
		nTok = CParserBin::FindToken(nTok, pBin->m_Tokens.size()-1, &pBin->m_Tokens[0], eT_include);
		if (nTok >= 0)
		{
			nTok++;
			uint32 nTokName = pBin->m_Tokens[nTok];
			const char *szNameInc = CParserBin::GetString(nTokName, pBin->m_TokenTable);
			if (!stricmp(szNameInc, szShaderName))
				break;
			SShaderBin *pBinIncl = gRenDev->m_cEF.m_Bin.GetBinShader(szNameInc, true, 0);
			bool bAffect = sCheckAffecting_r(pBinIncl, szShaderName);
			if (bAffect)
				break;
		}
	}

	}
  return (nTok >= 0);
}

bool CShaderMan::mfReloadFile(const char *szPath, const char *szName, int nFlags)
{
	CHWShader::mfFlushPendedShadersWait(-1);

	m_nFrameForceReload++;

	const char *szExt = fpGetExtension(szName);
	if (!stricmp(szExt, ".cfx"))
	{
		m_bReload = true;
		char szShaderName[256];
		int nSize = (int)(szExt-szName);
		strncpy(szShaderName, szName, nSize);
		szShaderName[nSize] = 0;
		strlwr(szShaderName);

		// Check if this shader already loaded
		CBaseResource *pBR = CBaseResource::GetResource(CShader::mfGetClassName(), szShaderName, false);
		if (pBR)
		{
			CShader *pShader = (CShader *)pBR;
			pShader->Reload(nFlags, szShaderName);
		}
		m_bReload = false;
	}
	else if (!stricmp(szExt, ".cfi"))
	{
		CCryNameTSCRC Name = CShader::mfGetClassName();
		SResourceContainer *pRL = CBaseResource::GetResourcesForClass(Name);
		if (pRL)
		{
			m_bReload = true;
			char szShaderName[256];
			int nSize = (int)(szExt-szName);
			strncpy(szShaderName, szName, nSize);
			szShaderName[nSize] = 0;
			strlwr(szShaderName);
			SShaderBin *pBin = m_Bin.GetBinShader(szShaderName, true, 0);
			bool bAffect = false;

			ResourcesMapItor itor;
			for (itor=pRL->m_RMap.begin(); itor!=pRL->m_RMap.end(); itor++)
			{	
				CShader *sh = (CShader *)itor->second;
				if (!sh || !sh->GetName()[0])
					continue;
				pBin = m_Bin.GetBinShader(sh->GetName(), false, 0);
				if (!pBin)
					continue;
				bAffect = sCheckAffecting_r(pBin, szShaderName);
				if (bAffect)
					sh->Reload(nFlags | FRO_FORCERELOAD, sh->GetName());
			}
		}
		m_bReload = false;
	}

	return false;
}

//=============================================================================

void CShaderMan::mfFillGenMacroses(SShaderGen *shG, TArray<char>& buf, uint64 nMaskGen)
{
	uint32 i;

	if (!nMaskGen || !shG)
		return;

	for (i=0; i<shG->m_BitMask.Num(); i++)
	{
		if (shG->m_BitMask[i]->m_Mask & nMaskGen)
		{
			char macro[256];
#if defined(__GNUC__) || defined(CAFE)
			sprintf(macro, "#define %s 0x%llx\n", shG->m_BitMask[i]->m_ParamName.c_str(), (unsigned long long)shG->m_BitMask[i]->m_Mask);
#else
			sprintf(macro, "#define %s 0x%I64x\n", shG->m_BitMask[i]->m_ParamName.c_str(), (uint64)shG->m_BitMask[i]->m_Mask);
#endif
			int size = strlen(macro);
			int nOffs = buf.Num();
			buf.Grow(size);
			memcpy(&buf[nOffs], macro, size);
		}
	}
}


bool CShaderMan::mfModifyGenFlags(CShader *efGen, const SRenderShaderResources *pRes, uint64& nMaskGen, uint64& nMaskGenH )
{
	if (!efGen || !efGen->m_ShaderGenParams)
	return false;
	uint64 nAndMaskHW = -1;
	uint64 nMaskGenHW = 0;

	// Remove non-used flags first
	unsigned int i = 0;
	SShaderGen *pGen = efGen->m_ShaderGenParams;
	int j;
  
	//char _debug_[256];
	//sprintf( _debug_, "curr shadergen %I64x %I64x\n", nMaskGen, nMaskGenH);
	//OutputDebugString(_debug_);

	if( nMaskGen )
	{
		for (j=0; j<64; j++)
		{
				uint64 nMask = (((uint64)1)<<j);
			if (nMaskGen & nMask)
			{        
			for (i=0; i<pGen->m_BitMask.Num(); i++)
			{
				SShaderGenBit *pBit = pGen->m_BitMask[i];
				if (pBit->m_Mask & nMask)
				break;
			}

			if (i == pGen->m_BitMask.Num())
				nMaskGen &= ~nMask;

			}
		}
	}

	for (i=0; i<pGen->m_BitMask.Num(); i++)
	{
		SShaderGenBit *pBit = pGen->m_BitMask[i];
		if (!pBit || (!pBit->m_nDependencySet && !pBit->m_nDependencyReset))
			continue;
		if (pRes)
		{
			if (pBit->m_nDependencySet & SHGD_TEX_BUMP)
			{
			if (!pRes->IsEmpty(EFTT_BUMP))
				nMaskGen |= pBit->m_Mask;
			}
			if (pBit->m_nDependencyReset & SHGD_TEX_BUMP)
			{
			if (pRes->IsEmpty(EFTT_BUMP))
				nMaskGen &= ~pBit->m_Mask;
			}
			if (pBit->m_nDependencySet & SHGD_TEX_HEIGHTMAP)
			{
			if (!pRes->IsEmpty(EFTT_BUMP_HEIGHT))
				nMaskGen |= pBit->m_Mask;
			}
			if (pBit->m_nDependencyReset & SHGD_TEX_HEIGHTMAP)
			{
			if (pRes->IsEmpty(EFTT_BUMP_HEIGHT))
				nMaskGen &= ~pBit->m_Mask;
			}

			if (pBit->m_nDependencySet & SHGD_TEX_DETAIL)
			{
			if ( !pRes->IsEmpty(EFTT_DETAIL_OVERLAY) )
				nMaskGen |= pBit->m_Mask;
			}
			if (pBit->m_nDependencyReset & SHGD_TEX_DETAIL)
			{
			if ( pRes->IsEmpty(EFTT_DETAIL_OVERLAY) )
				nMaskGen &= ~pBit->m_Mask;
			}

			if (pBit->m_nDependencySet & SHGD_TEX_BUMPDIF)
			{
			if (!pRes->IsEmpty(EFTT_BUMP_DIFFUSE))
				nMaskGen |= pBit->m_Mask;
			}
			if (pBit->m_nDependencyReset & SHGD_TEX_BUMPDIF)
			{
			if (pRes->IsEmpty(EFTT_BUMP_DIFFUSE))
				nMaskGen &= ~pBit->m_Mask;
			}

			if (pBit->m_nDependencySet & SHGD_TEX_GLOSS)
			{
			if (!pRes->IsEmpty(EFTT_GLOSS))
				nMaskGen |= pBit->m_Mask;
			}
			if (pBit->m_nDependencyReset & SHGD_TEX_GLOSS)
			{
			if (pRes->IsEmpty(EFTT_GLOSS))
				nMaskGen &= ~pBit->m_Mask;
			}

			if (pBit->m_nDependencySet & SHGD_TEX_ENVCM)
			{
			if (!pRes->IsEmpty(EFTT_ENV))
				nMaskGen |= pBit->m_Mask;
			}
			if (pBit->m_nDependencyReset & SHGD_TEX_ENVCM)
			{
			if (pRes->IsEmpty(EFTT_ENV))
				nMaskGen &= ~pBit->m_Mask;
			}

			if (pBit->m_nDependencySet & SHGD_TEX_SUBSURFACE)
			{
			if (!pRes->IsEmpty(EFTT_SUBSURFACE))
				nMaskGen |= pBit->m_Mask;
			}
			if (pBit->m_nDependencyReset & SHGD_TEX_SUBSURFACE)
			{
			if (pRes->IsEmpty(EFTT_SUBSURFACE))
				nMaskGen &= ~pBit->m_Mask;
			}

			if (pBit->m_nDependencySet & SHGD_TEX_DECAL)
			{
			if (!pRes->IsEmpty(EFTT_DECAL_OVERLAY))
				nMaskGen |= pBit->m_Mask;
			}
			if (pBit->m_nDependencyReset & SHGD_TEX_DECAL)
			{
			if (pRes->IsEmpty(EFTT_DECAL_OVERLAY))
				nMaskGen &= ~pBit->m_Mask;
			}

			if (pBit->m_nDependencySet & SHGD_TEX_CUSTOM)
			{
			if (!pRes->IsEmpty(EFTT_CUSTOM))
				nMaskGen |= pBit->m_Mask;
			}
			if (pBit->m_nDependencyReset & SHGD_TEX_CUSTOM)
			{
			if (pRes->IsEmpty(EFTT_CUSTOM))
				nMaskGen &= ~pBit->m_Mask;
			}

			if (pBit->m_nDependencySet & SHGD_TEX_CUSTOM_SECONDARY)
			{
			if (!pRes->IsEmpty(EFTT_CUSTOM_SECONDARY))
				nMaskGen |= pBit->m_Mask;
			}
			if (pBit->m_nDependencyReset & SHGD_TEX_CUSTOM_SECONDARY)
			{
			if (pRes->IsEmpty(EFTT_CUSTOM_SECONDARY))
				nMaskGen &= ~pBit->m_Mask;
			}

			if (pBit->m_nDependencySet & SHGD_LM_DIFFUSE)
			{
			const ColorF *pMt = (ColorF *)&pRes->m_Constants[eHWSC_Pixel][PS_DIFFUSE_COL];
			if (pMt->Luminance() >= 0.05f)
				nMaskGen |= pBit->m_Mask;
			}
			if (pBit->m_nDependencyReset & SHGD_LM_DIFFUSE)
			{
			const ColorF *pMt = (ColorF *)&pRes->m_Constants[eHWSC_Pixel][PS_DIFFUSE_COL];
			if (pMt && pMt->Luminance() < 0.05f)
				nMaskGen &= ~pBit->m_Mask;
			}
		}

		// Specific case - for user gl flags (eg: TEMP_TERRAIN, TEMP_VEGETATION)
		// this is needed since we now use common shader global flags - else define inside shader.cfi will override correct shared value
		if (pBit->m_nDependencySet & SHGD_USER_ENABLED)
			nMaskGen |= pBit->m_Mask;

		//if (m_nCombinationsProcess < 0 || m_bActivatePhase)
		{
			if (pBit->m_nDependencySet & SHGD_HW_BILINEARFP16)
			{
				nAndMaskHW &= ~pBit->m_Mask;
				if (gRenDev->m_bDeviceSupportsFP16Filter)
					nMaskGenHW |= pBit->m_Mask;
			}
			if (pBit->m_nDependencyReset & SHGD_HW_BILINEARFP16)
			{
				nAndMaskHW &= ~pBit->m_Mask;
				if (!gRenDev->m_bDeviceSupportsFP16Filter)
					nMaskGenHW &= ~pBit->m_Mask;
			}
			if (pBit->m_nDependencySet & SHGD_HW_SEPARATEFP16)
			{
				nAndMaskHW &= ~pBit->m_Mask;
				if (gRenDev->m_bDeviceSupportsFP16Separate)
					nMaskGenHW |= pBit->m_Mask;
			}
			if (pBit->m_nDependencyReset & SHGD_HW_SEPARATEFP16)
			{
				nAndMaskHW &= ~pBit->m_Mask;
				if (!gRenDev->m_bDeviceSupportsFP16Separate)
					nMaskGenHW &= ~pBit->m_Mask;
			}

				if (CParserBin::m_bShaderCacheGen)
				{
					// during shader cache gen, disable the special features in non D3D11 mode, and just accept
					// the lines as they come in D3D11 mode
					if (CParserBin::m_nPlatform != SF_D3D11)
					{
						if (pBit->m_nDependencySet & SHGD_HW_TESSELLATION)
							nAndMaskHW &= ~pBit->m_Mask;
						if (pBit->m_nDependencySet & SHGD_HW_WATER_TESSELLATION)
							nAndMaskHW &= ~pBit->m_Mask;
						/*if (pBit->m_nDependencySet & SHGD_HW_SILHOUETTE_POM)
							nAndMaskHW &= ~pBit->m_Mask;*/
					}
				} 
				else 
				{
					if (pBit->m_nDependencySet & SHGD_HW_TESSELLATION)
					{
						nAndMaskHW &= ~pBit->m_Mask;
						if (CParserBin::m_nPlatform == SF_D3D11)
							nMaskGenHW |= pBit->m_Mask;
					}
					if (pBit->m_nDependencyReset & SHGD_HW_TESSELLATION)
					{
						nAndMaskHW &= ~pBit->m_Mask;
						if (CParserBin::m_nPlatform != SF_D3D11)
							nMaskGenHW &= ~pBit->m_Mask;
					}

					PREFAST_SUPPRESS_WARNING(6326)
					bool bWaterTessHW = CParserBin::m_bShaderCacheGen || (CRenderer::CV_r_WaterTessellationHW != 0);
					if (pBit->m_nDependencySet & SHGD_HW_WATER_TESSELLATION)
					{
						nAndMaskHW &= ~pBit->m_Mask;
						if (bWaterTessHW)
							nMaskGenHW |= pBit->m_Mask;
					}
					if (pBit->m_nDependencyReset & SHGD_HW_WATER_TESSELLATION)
					{
						nAndMaskHW &= ~pBit->m_Mask;
						if (!bWaterTessHW)
							nMaskGenHW &= ~pBit->m_Mask;
					}	
				}
		}
	}
	nMaskGen &= nAndMaskHW;
	nMaskGenH |= nMaskGenHW;

	//sprintf( _debug_, "remap shadergen %I64x %I64x\n", nMaskGen, nMaskGenH);
	//OutputDebugString(_debug_);

	return true;
}

bool CShaderMan::mfUpdateTechnik (SShaderItem& SI, CCryNameTSCRC& Name)
{
	CShader *pSH = (CShader *)SI.m_pShader;
	if (!(pSH->m_Flags & EF_LOADED))
	return false;
	uint32 i;
	for (i=0; i<pSH->m_HWTechniques.Num(); i++)
	{
		SShaderTechnique *pTech = pSH->m_HWTechniques[i];
		//if (!(pTech->m_Flags & FHF_PUBLIC))
		//  continue;
		if (pTech->m_NameCRC == Name)
			break;
	}
	if (i == pSH->m_HWTechniques.Num())
	{
		SI.m_nTechnique = -1;
		Warning("ERROR: CShaderMan::mfUpdateTechnik: couldn't find public technique for shader '%s'", pSH->GetName());
	}
	else
	{
		SI.m_nTechnique = i;
	}

	return true;
}

//char s_NameEf[1024];
//uint64 s_nMaskGen;
//SRenderShaderResources *s_pResource;

SShaderItem CShaderMan::mfShaderItemForName (const char *nameEf, bool bShare, int flags, SInputShaderResources *Res, uint64 nMaskGen)
{
	MEMSTAT_CONTEXT_FMT(EMemStatContextTypes::MSC_Shader, 0, "ShaderItem (%s)", nameEf);

	SShaderItem SI;
	//strcpy(s_NameEf, nameEf);
	//s_nMaskGen = nMaskGen;

	SRenderShaderResources *pResource = NULL;
	if (Res)
	{
		SI.m_pShaderResources = mfCreateShaderResources(Res, bShare);
		pResource = (SRenderShaderResources *)SI.m_pShaderResources;
		pResource->m_ShaderParams = Res->m_ShaderParams;
		m_pCurInputResources = Res;
	}
	//s_pResource = pResource;

	string strShader = nameEf;
	string strTechnique;
	string strNew = strShader.SpanExcluding(".");
	if (strNew.size() != strShader.size())
	{
		string second = string(&strShader.c_str()[strNew.size()+1]);
		strShader = strNew;
		strTechnique = second;
	}

	if (SI.m_pShaderResources)
	{
		mfRefreshResources((SRenderShaderResources *)SI.m_pShaderResources,true);
	}

	char sNewShaderName[256]="";
	char shadName[256];
	if (nameEf && nameEf[0])
	{
		strncpy(shadName, strShader.c_str(), 256);
	}
	else
	{
		shadName[0] = 0;
	}

	SI.m_pShader = mfForName(shadName, flags, (SRenderShaderResources *)SI.m_pShaderResources, nMaskGen);
	CShader *pSH = (CShader *)SI.m_pShader;

	// Get technique
	if (strTechnique.size())
	{
		CCryNameTSCRC nTech(strTechnique.c_str());
		if (!mfUpdateTechnik(SI, nTech))
		{
			SI.m_nTechnique = nTech.get(); // Postpone
		}
	}
	SI.m_nPreprocessFlags = -1;
	if (Res)
	{
		SI.m_pShaderResources = pResource;
		if (pResource)
			pResource->CreateModifiers(Res);
	}
	m_pCurInputResources = NULL;
	return SI;
}


CShader *CShaderMan::mfForName (const char *nameSh, int flags, const SRenderShaderResources *Res, uint64 nMaskGen)
{
	CShader *ef, *efGen;
	int id;

	if (!nameSh || !nameSh[0])
	{
		Warning("Warning: CShaderMan::mfForName: NULL name\n");
		m_DefaultShader->AddRef();
		return m_DefaultShader;
	}

	char nameEf[256];
	char nameNew[256];
	char nameRes[256];

	uint64 nMaskGenHW = 0;

	if (!nMaskGen)
		strncpy(nameEf, nameSh, 256);
	else
		strcpy(nameEf, nameSh);

	strcpy(nameRes, nameEf);
	if (CParserBin::m_nPlatform == SF_D3D10)
		strcat(nameRes, "(DX0)");
	else
		if (CParserBin::m_nPlatform == SF_D3D11)
			strcat(nameRes, "(DX1)");
		else
			if (CParserBin::m_nPlatform == SF_XENON)
				strcat(nameRes, "(X)");
			else
				if (CParserBin::m_nPlatform == SF_PS3)
					strcat(nameRes, "(P)");
				else
					if (CParserBin::m_nPlatform == SF_CAFE)
						strcat(nameRes, "(CAFE)");

	ef = NULL;
	efGen = NULL;

	// Check if this shader already loaded
	CBaseResource *pBR = CBaseResource::GetResource(CShader::mfGetClassName(), nameRes, false);
	bool bGenModified = false;
	ef = (CShader *)pBR;
	if (ef && ef->m_ShaderGenParams)
	{
		efGen = ef;
		//if (!(flags & EF_RELOAD))
		//  nMaskGen = gRenDev->EF_GetRemapedShaderMaskGen(nameSh, nMaskGen | nMaskGenHW);
		mfModifyGenFlags(efGen, Res, nMaskGen, nMaskGenHW);
		bGenModified = true;
#if defined(PS3) || defined(__GNUC__)
		sprintf(nameNew, "%s(%llx)", nameRes, (long long unsigned)nMaskGen);
#else
		sprintf(nameNew, "%s(%I64x)", nameRes, nMaskGen);
#endif
		pBR = CBaseResource::GetResource(CShader::mfGetClassName(), nameNew, false);
		ef = (CShader *)pBR;
		if (ef)
		{
			// Update the flags if HW specs changed
			ef->m_nMaskGenFX = nMaskGen | nMaskGenHW;
			assert(ef->m_pGenShader == efGen);
		}
	}

	if (ef)
	{
		if (!(flags & EF_RELOAD))
		{
			ef->AddRef();
			ef->m_Flags |= flags;
			return ef;
		}
		else
		{
			ef->mfFree();
			ef->m_Flags |= EF_RELOADED;
		}
	}

	if (!efGen)
	{
		sprintf(nameNew, "Shaders/%s.ext", nameEf);
		SShaderGen *pShGen = mfCreateShaderGenInfo(nameEf, false);

		if (pShGen)
		{
			efGen = mfNewShader(nameRes);
			efGen->SetRefCounter(0);      // Hack: to avoid leaks in shader-gen's
			efGen->m_NameShader = nameRes;
			efGen->m_ShaderGenParams = pShGen;
		}
	}
	if (!(flags & EF_RELOAD) || !ef)
	{
		if (efGen)
		{
		  // Change gen flags based on dependency on resources info
			if (!bGenModified)
			{
					//nMaskGen = gRenDev->EF_GetRemapedShaderMaskGen(nameSh, nMaskGen | nMaskGenHW); 
				mfModifyGenFlags(efGen, Res, nMaskGen, nMaskGenHW);
			}
#if defined(PS3) || defined(__GNUC__) || defined(CAFE)
			sprintf(nameNew, "%s(%llx)", nameRes, (long long unsigned)nMaskGen);
#else
			sprintf(nameNew, "%s(%I64x)", nameRes, nMaskGen);
#endif
			ef = mfNewShader(nameNew);
			if (!ef)
				return m_DefaultShader;

			ef->m_nMaskGenFX = nMaskGen | nMaskGenHW;
			ef->m_pGenShader = efGen;
		}
		if (efGen && ef)
		{
			assert(efGen != ef);
			if (!efGen->m_DerivedShaders)
				efGen->m_DerivedShaders = new std::vector<CShader *>;
			efGen->m_DerivedShaders->push_back(ef);
			efGen->AddRef();
		}
		if (!ef)
		{
			ef = mfNewShader(nameRes);
			if (!ef)
				return m_DefaultShader;
		}
	}
	id = ef->GetID();
	ef->m_NameShader = nameEf;
	ef->m_NameShaderICRC = gEnv->pSystem->GetCrc32Gen()->GetCRC32Lowercase(nameEf);

	bool bSuccess = false;
#ifndef NULL_RENDERER
	// Check for the new cryFX format
	sprintf(nameNew, "%sCryFX/%s.cfx", m_ShadersPath, nameEf);
	ef->m_NameFile = nameNew;
	ef->m_Flags |= flags;
	gRenDev->m_pRT->RC_ParseShader(ef, nMaskGen | nMaskGenHW, flags, (SRenderShaderResources *)Res);
	return ef;
#endif
  
	return ef;
}

void CShaderMan::RT_ParseShader(CShader *pSH, uint64 nMaskGen, uint32 flags, SRenderShaderResources *pRes)
{
	MEMSTAT_CONTEXT(EMemStatContextTypes::MSC_Other, 0, "ParseShader");

  bool bSuccess = false;
#ifdef SHADERS_SERIALIZING
  bSuccess = ImportShader(pSH);
#endif
  if (!bSuccess)
  {
#if !defined(SHADER_NO_SOURCES)
    SShaderBin *pBin = m_Bin.GetBinShader(pSH->m_NameShader, false, 0);
    if (pBin)
#endif
    {
#if !defined(SHADER_NO_SOURCES)
      if (flags & EF_FORCE_RELOAD)
			{
				uint32 nCRC32 = pBin->ComputeCRC();
        if (nCRC32 != pBin->m_CRC32)
				{
					FXShaderBinValidCRCItor itor = gRenDev->m_cEF.m_Bin.m_BinValidCRCs.find(pBin->m_dwName);
					if (itor == gRenDev->m_cEF.m_Bin.m_BinValidCRCs.end())
						gRenDev->m_cEF.m_Bin.m_BinValidCRCs.insert(FXShaderBinValidCRCItor::value_type(pBin->m_dwName, false));

					m_Bin.DeleteFromCache(pBin);
					pBin = m_Bin.GetBinShader(pSH->m_NameShader, false, nCRC32);
				}
			}
#endif
      bSuccess = m_Bin.ParseBinFX(pBin, pSH, nMaskGen);
#ifdef SHADERS_SERIALIZING
      if (bSuccess)
        ExportShader(pSH);
#endif
    }
    else
      pSH->m_Flags |= EF_NOTFOUND;
  }
  pSH->m_Flags |= EF_LOADED;
  {
    if (gRenDev->m_cEF.m_nCombinationsProcess<0)
    {
      //SRenderShaderResources *pTempR = gRenDev->m_RP.m_pShaderResources;
      //CShader *pTempSH = gRenDev->m_RP.m_pShader;
      SShaderCombination cmb;
      cmb.m_LTMask = 0;
      cmb.m_RTMask = 0;
      cmb.m_MDMask = 0;
      cmb.m_MDVMask = 0;
      if (pRes && pRes->m_pDeformInfo)
        cmb.m_MDVMask |= pRes->m_pDeformInfo->m_eType;
      cmb.m_MDVMask |= pSH->m_nMDV;
      bool nRes = pSH->mfPrecache(cmb, false, false, pRes);
    }
  }
}

